package fr.pud.client.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;

import fr.pud.client.i18n.LanguagesConstants;
import fr.pud.client.images.ImagesDatabase;
import fr.pud.client.model.Fleet;
import fr.pud.client.model.PUDStation;
import fr.pud.client.model.PUDStationDatabase;
import fr.pud.client.model.Queries;
import fr.pud.client.model.Query;
import fr.pud.client.model.Route;
import fr.pud.client.model.Routes;
import fr.pud.client.model.Vehicle;

/**
 * Apr 9, 2012 - Projet_Ose.
 * @author Simon Devineau, Adrien Hierry, Leopold Houdin, Pierre Reliquet
 *         Ecole des Mines de Nantes
 *         MainFrame.java
 *         This class creates a single frame which represents the view of the
 *         program.
 */
public class MainFrame extends JFrame {
    /**
     * An instance of the MainFrame used to be sure that there will be only one
     * frame in the program.
     */
    private static MainFrame   singleton         = null;
    /**
     * The default latitude corresponds to Nantes, Loire-Atlantique,France
     */
    public final static double DEFAULT_LATITUDE  = 47.21806;
    /**
     * The default longitude corresponds to Nantes, Loire-Atlantique,France
     */
    public final static double DEFAULT_LONGITUDE = -1.55278;
    /**
     * The default zoom enables to have a quick overview of Nantes, France
     */
    public final static int    DEFAULT_ZOOM      = 12;
    /**
     * The location of the help file
     */
    public static final String PATH_HELP_FILE    = "help/help_"
                                                         + System.getProperty("user.language")
                                                         + ".html";
    /**
     * A JMapViewerExtended is static and accessible from everywhere
     */
    private static final long  serialVersionUID  = -9185848921871589568L;

    /**
     * @return the defaultLatitude
     */
    public static double getDefaultLatitude() {
        return DEFAULT_LATITUDE;
    }

    /**
     * @return the defaultLongitude
     */
    public static double getDefaultLongitude() {
        return DEFAULT_LONGITUDE;
    }

    /**
     * @return the defaultZoom
     */
    public static int getDefaultZoom() {
        return DEFAULT_ZOOM;
    }

    public static MainFrame getMainFrame() {
        initialization();
        return singleton;
    }

    /**
     * @return the pathHelpFile
     */
    public static String getPathHelpFile() {
        return PATH_HELP_FILE;
    }

    /**
     * @return the serial version uid
     */
    public static long getSerialversionuid() {
        return serialVersionUID;
    }

    /**
     * @return the singleton
     */
    public static MainFrame getSingleton() {
        return singleton;
    }

    private static void initialization() {
        if (singleton == null) {
            singleton = new MainFrame();
        }
    }

    /**
     * A JTabbedPane to add tab to our frame.
     */
    private JTabbedPane tabbedPane;
    private JEditorPane editorPane;
    private JScrollPane editorScrollPane;
    /**
     * A menu item to quit the program
     */
    private JMenuItem   quit;
    /**
     * The toolbar of the frame
     */
    private JToolBar    toolBar                              = new JToolBar();
    /**
     * A button on the toolbar to print an xml file
     */
    private JButton     printXMLFileToolBar                  = new JButton();
    /**
     * A button to close the program
     */
    private JButton     closeSoftwareToolBar                 = new JButton();
    /**
     * A button to open a file with a list of address
     */
    private JButton     loadAddressFileToolbar               = new JButton();
    /**
     * The JtextField where the user types an address which search.
     */
    private JTextField  goToText                             = new JTextField(
                                                                     40);
    /**
     * The JButton which launch this search.
     */
    private JButton     goToButton                           = new JButton(
                                                                     (String) LanguagesConstants.LANGUAGE
                                                                             .getObject(LanguagesConstants.GO_TO));
    /**
     * A JButton to open a existing fleet
     */
    private JButton     addVehicleToolBar                    = new JButton();
    /**
     * The button used to launch the computation
     */
    private JButton     launchComputation                    = new JButton();
    /**
     * A button to open the frame to create a query.
     */
    private JButton     createQuery                          = new JButton();
    /**
     * The button to open the frame which allows to the user to choose the route
     * to hide.
     */
    private JButton     buttonHideOrDisplayRoute             = new JButton(
                                                                     LanguagesConstants.LANGUAGE
                                                                             .getString(LanguagesConstants.OPEN));
    /*
     * Menu
     */
    /**
     * The JMenuItem which print the results from an xml file.
     */
    private JMenuItem   printXMLFile                         = new JMenuItem();
    /**
     * The JMenuItem to add a vehicle to the fleet.
     */
    private JMenuItem   addVehicle                           = new JMenuItem();
    /**
     * The JMenuItem to create a query for the server.
     */
    private JMenuItem   menuItemCreateQuery                  = new JMenuItem();
    /**
     * The JMenuItem to save the current fleet.
     */
    private JMenuItem   saveFleet                            = new JMenuItem();
    /**
     * The JMenuItem to save the current queries.
     */
    private JMenuItem   saveQueries                          = new JMenuItem();
    /**
     * The JMenuItem to save the current route.
     */
    private JMenuItem   saveRoutes                           = new JMenuItem();
    /**
     * The JMenuItem to load a fleet which was saved.
     */
    private JMenuItem   loadFleet                            = new JMenuItem();
    /**
     * The JMenuItem to load a route which was saved.
     */
    private JMenuItem   loadRoutes                           = new JMenuItem();
    /**
     * The JMenuItem to display or hide the Queries
     */
    private JMenuItem   changeVisibilityQueries              = new JMenuItem();
    /**
     * The JMenuItem to display or hide the addresses suggestions
     */
    private JMenuItem   changeVisibilityAddressesSuggestions = new JMenuItem();
    /**
     * The JMenuItem to display or hide the results (MapRoutes)
     */
    private JMenuItem   changeVisibilityMapRoutes            = new JMenuItem();
    /**
     * The JMenuItem to load queries which was saved.
     */
    private JMenuItem   loadQueries                          = new JMenuItem();
    /**
     * A button to open a file with a list of address
     */
    private JMenuItem   loadAddressFile                      = new JMenuItem();

    /**
     * Default constructor which set up the GUI
     */
    private MainFrame() {
        this.setTitle(LanguagesConstants.LANGUAGE
                .getString(LanguagesConstants.TITLE));
        this.prepareMenu();
        this.prepareLayout();
        this.setHelp();
        this.prepareTab();
        // Standard configuration
        this.placeFrame();
        this.prepareToolBar();
        this.setVisible(true);
        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    }

    /**
     * @return the addVehicle
     */
    public JMenuItem getAddVehicle() {
        return this.addVehicle;
    }

    /**
     * @return the addVehicleToolBar
     */
    public JButton getAddVehicleToolBar() {
        return this.addVehicleToolBar;
    }

    /**
     * @return the buttonHideOrDisplayRoute
     */
    public JButton getButtonHideOrDisplayRoute() {
        return this.buttonHideOrDisplayRoute;
    }

    /**
     * @return the changeVisibilityAddressesSuggestions
     */
    public JMenuItem getChangeVisibilityAddressesSuggestions() {
        return this.changeVisibilityAddressesSuggestions;
    }

    /**
     * @return the changeVisibilityMapRoutes
     */
    public JMenuItem getChangeVisibilityMapRoutes() {
        return this.changeVisibilityMapRoutes;
    }

    /**
     * @return the changeVisibilityQueries
     */
    public JMenuItem getChangeVisibilityQueries() {
        return this.changeVisibilityQueries;
    }

    /**
     * @return the button close of the toolbar.
     */
    public JButton getCloseSoftwareToolBar() {
        initialization();
        return this.closeSoftwareToolBar;
    }

    /**
     * @return the createQuery
     */
    public JButton getCreateQuery() {
        return this.createQuery;
    }

    /**
     * @return the editorPane
     */
    public JEditorPane getEditorPane() {
        return this.editorPane;
    }

    /**
     * @return the editorScrollPane
     */
    public JScrollPane getEditorScrollPane() {
        return this.editorScrollPane;
    }

    public JButton getGoToButton() {
        initialization();
        return this.goToButton;
    }

    public JTextField getGoToText() {
        initialization();
        return this.goToText;
    }

    /**
     * @return the launchComputation
     */
    public JButton getLaunchComputation() {
        return this.launchComputation;
    }

    /**
     * @return the loadAddressFile
     */
    public JMenuItem getLoadAddressFile() {
        return this.loadAddressFile;
    }

    public JMenuItem getLoadAddressFiler() {
        return this.loadAddressFile;
    }

    public JButton getLoadAddressFileToolbar() {
        return this.loadAddressFileToolbar;
    }

    /**
     * @return the loadFleet
     */
    public JMenuItem getLoadFleet() {
        return this.loadFleet;
    }

    /**
     * @return the loadQueries
     */
    public JMenuItem getLoadQueries() {
        return this.loadQueries;
    }

    /**
     * @return the loadRoutes
     */
    public JMenuItem getLoadRoutes() {
        return this.loadRoutes;
    }

    /**
     * @return the menuItemCreateQuery
     */
    public JMenuItem getMenuItemCreateQuery() {
        return this.menuItemCreateQuery;
    }

    public JMenuItem getPrintXMLFile() {
        initialization();
        return this.printXMLFile;
    }

    public JButton getPrintXMLFileToolBar() {
        initialization();
        return this.printXMLFileToolBar;
    }

    public JMenuItem getQuit() {
        initialization();
        return this.quit;
    }

    /**
     * @return the saveFleet
     */
    public JMenuItem getSaveFleet() {
        return this.saveFleet;
    }

    /**
     * @return the saveQueries
     */
    public JMenuItem getSaveQueries() {
        return this.saveQueries;
    }

    /**
     * @return the saveRoutes
     */
    public JMenuItem getSaveRoutes() {
        return this.saveRoutes;
    }

    /**
     * @return the tabbedPane
     */
    public JTabbedPane getTabbedPane() {
        return this.tabbedPane;
    }

    /**
     * @return the toolBar
     */
    public JToolBar getToolBar() {
        return this.toolBar;
    }

    /**
     * Put the frame in the middle of the screen
     */
    private void placeFrame() {
        this.setSize(Toolkit.getDefaultToolkit().getScreenSize());
        this.setLocation(0, 0);
    }

    /**
     * Prepare the tab where the database of PUDStation will be written
     */
    private void prepareDatabaseView() {
        JPanel databasePanel = new JPanel();
        databasePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        databasePanel.setLayout(new BoxLayout(databasePanel, BoxLayout.Y_AXIS));
        JLabel databaseLabel = new JLabel(
                LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.PUDSTATION_DATABASE));
        databaseLabel.setIcon(ImagesDatabase.ADDRESSES);
        databasePanel.add(databaseLabel);
        databasePanel.add(new JScrollPane(new SummarizeInfo<PUDStation>(
                PUDStationDatabase.getInstance().getStations(),
                PUDStationDatabase.getInstance())));
        this.tabbedPane.add(LanguagesConstants.LANGUAGE
                .getString(LanguagesConstants.PUDSTATION_DATABASE),
                databasePanel);
    }

    /**
     * Prepare the file menu and add it to menu, the menu contains also the item
     * which enables to print xml results file
     * @param menu
     *            JMenuBar, the menu where is added the file menu
     */
    private void prepareFile(JMenuBar menu) {
        JMenu file = new JMenu(
                (String) LanguagesConstants.LANGUAGE
                        .getObject(LanguagesConstants.FILE));
        file.add(this.printXMLFile);
        file.add(this.loadAddressFile);
        this.quit = new JMenuItem();
        file.add(this.quit);
        menu.add(file);
    }

    /**
     * Prepare the tab where a view of the current Fleet and Queries is
     * available.
     */
    private void prepareFleetAndQueriesView() {
        // About the Fleet
        JPanel fleetPanel = new JPanel();
        fleetPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        fleetPanel.setLayout(new BoxLayout(fleetPanel, BoxLayout.Y_AXIS));
        JLabel fleetLabel = new JLabel(
                LanguagesConstants.LANGUAGE.getString(LanguagesConstants.FLEET));
        fleetLabel.setIcon(ImagesDatabase.TRUCK);
        fleetPanel.add(fleetLabel);
        fleetPanel.add(new JScrollPane(new SummarizeInfo<Vehicle>(Fleet
                .getInstance().getVehicles(), Fleet.getInstance())));
        // About the Queries
        JPanel queriesPanel = new JPanel();
        queriesPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        queriesPanel.setLayout(new BoxLayout(queriesPanel, BoxLayout.Y_AXIS));
        JLabel queriesLabel = new JLabel(
                LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.QUERIES));
        queriesLabel.setIcon(ImagesDatabase.ROUND);
        queriesPanel.add(queriesLabel);
        queriesPanel.add(new JScrollPane(new JScrollPane(
                new SummarizeInfo<Query>(Queries.getInstance().getQueries(),
                        Queries.getInstance()))));
        this.tabbedPane
                .add(LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.FLEET), fleetPanel);
        this.tabbedPane.add(LanguagesConstants.LANGUAGE
                .getString(LanguagesConstants.QUERIES), queriesPanel);
    }

    /**
     * Prepare the menu fleet
     * @param menu
     *            JMenuBar, the menu where the all the items related to the
     *            fleet will be placed
     */
    private void prepareFleetMenuBar(JMenuBar menu) {
        JMenu generate = new JMenu(
                LanguagesConstants.LANGUAGE.getString(LanguagesConstants.FLEET));
        generate.add(this.addVehicle);
        generate.add(this.menuItemCreateQuery);
        generate.add(this.saveFleet);
        generate.add(this.loadFleet);
        menu.add(generate);
    }

    /**
     * Configure the GUI with a BorderLayout
     */
    private void prepareLayout() {
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.getContentPane().setLayout(new BorderLayout());
        this.setBackground(Color.LIGHT_GRAY);
        try {
            Image iconFrame = Toolkit.getDefaultToolkit().getImage(
                    ImagesDatabase.OSM_ICON_URL);
            this.setIconImage(iconFrame);
        }
        catch (Exception e) {
            System.err.println("Error while reading osmIcon.png");
        }
    }

    /**
     * Prepare the menu which allows to quit in a "clean way"
     */
    private void prepareMenu() {
        JMenuBar menu = new JMenuBar();
        this.setJMenuBar(menu);
        this.prepareFile(menu);
        this.prepareViewMenuBar(menu);
        this.prepareFleetMenuBar(menu);
        this.prepareQueriesMenuBar(menu);
        this.prepareRoutesMenuBar(menu);
    }

    /**
     * Prepare the menu queries
     * @param menu
     *            JMenuBar, the menu where the all the items related to the
     *            queries will be placed
     */
    private void prepareQueriesMenuBar(JMenuBar menu) {
        JMenu generate = new JMenu(
                LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.QUERIES));
        generate.add(this.menuItemCreateQuery);
        generate.add(this.saveQueries);
        generate.add(this.loadQueries);
        menu.add(generate);
    }

    /**
     * Prepare the menu queries
     * @param menu
     *            JMenuBar, the menu where the all the items related to the
     *            queries will be placed
     */
    private void prepareRoutesMenuBar(JMenuBar menu) {
        JMenu generate = new JMenu(
                LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.ROUTES));
        generate.add(this.saveRoutes);
        generate.add(this.loadRoutes);
        menu.add(generate);
    }

    /**
     * Prepare the tab where the results will be written
     */
    private void prepareRoutesView() {
        JPanel routesPanel = new JPanel();
        routesPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        routesPanel.setLayout(new BoxLayout(routesPanel, BoxLayout.Y_AXIS));
        JLabel routesLabel = new JLabel(
                LanguagesConstants.LANGUAGE
                        .getString(LanguagesConstants.ROUTES));
        routesLabel.setIcon(ImagesDatabase.ROAD);
        routesPanel.add(routesLabel);
        routesPanel.add(new JScrollPane(new SummarizeInfo<Route>(Routes
                .getInstance().getRoutes(), Routes.getInstance())));
        this.tabbedPane.add(LanguagesConstants.LANGUAGE
                .getString(LanguagesConstants.ROUTES), routesPanel);
    }

    /**
     * Prepare all the tab of the frame
     */
    private void prepareTab() {
        this.tabbedPane = new JTabbedPane();
        this.add(this.tabbedPane);
        MainPanel mapTab = new MainPanel();
        this.tabbedPane.add(
                LanguagesConstants.LANGUAGE.getString(LanguagesConstants.MAP),
                mapTab);
        this.prepareFleetAndQueriesView();
        this.prepareRoutesView();
        this.prepareDatabaseView();
        this.tabbedPane.add(
                LanguagesConstants.LANGUAGE.getString(LanguagesConstants.HELP),
                this.editorScrollPane);
    }

    /**
     * Prepare the toolbar of the main frame with all its components as :
     * -the button close, load address from a csv file, print results from xml,
     * add a vehicle,
     * - create a query for the server, launch the computation and the part for
     * the search of address.
     */
    private void prepareToolBar() {
        this.toolBar.add(this.closeSoftwareToolBar);
        this.toolBar.add(this.loadAddressFileToolbar);
        this.toolBar.add(this.printXMLFileToolBar);
        this.toolBar.add(this.addVehicleToolBar);
        this.toolBar.add(this.createQuery);
        this.toolBar.add(this.launchComputation);
        this.toolBar.add(this.buttonHideOrDisplayRoute);
        this.toolBar.add(this.goToText);
        this.toolBar.add(this.goToButton);
        this.add(this.toolBar, BorderLayout.NORTH);
    }

    /**
     * Prepare the menu fleet
     * @param menu
     *            JMenuBar, the menu where the all the items related to the
     *            fleet will be placed
     */
    private void prepareViewMenuBar(JMenuBar menu) {
        JMenu generate = new JMenu(
                LanguagesConstants.LANGUAGE.getString(LanguagesConstants.VIEW));
        generate.add(this.changeVisibilityQueries);
        generate.add(this.changeVisibilityAddressesSuggestions);
        generate.add(this.changeVisibilityMapRoutes);
        menu.add(generate);
    }

    /**
     * @param aAddVehicle
     *            the addVehicle to set
     */
    public void setAddVehicle(JMenuItem aAddVehicle) {
        this.addVehicle = aAddVehicle;
    }

    /**
     * @param aAddVehicleToolBar
     *            the addVehicleToolBar to set
     */
    public void setAddVehicleToolBar(JButton aAddVehicleToolBar) {
        this.addVehicleToolBar = aAddVehicleToolBar;
    }

    /**
     * Add the pane for the help part, the help is available in the same
     * languages as the complete software
     */
    private void setHelp() {
        this.editorPane = new JEditorPane();
        this.editorPane.setEditable(false);
        String helpResource = this.getClass().getResource(PATH_HELP_FILE)
                .toString();
        String helpURL = helpResource;
        if (helpURL != null) {
            try {
                this.editorPane.setPage(helpURL);
            }
            catch (IOException e) {
                System.err.println("Attempted to read a bad URL: " + helpURL);
            }
        }
        // Put the editor pane in a scroll pane.
        this.editorScrollPane = new JScrollPane(this.editorPane);
        this.editorScrollPane
                .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        this.editorScrollPane
                .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    }
}
